﻿namespace com.liyong
{
    using System;
    using System.Collections.Generic;
    using System.Runtime.CompilerServices;
    using System.Runtime.InteropServices;
    using UnityEngine;
    using UnityLog;

    public class CommandHandler : MonoBehaviour
    {
        private Dictionary<string, CmdHandler> cmdHandlers = new Dictionary<string, CmdHandler>();
        private List<Command> cmdList = new List<Command>();
        public static string COMMENT = "\r\n/* *******************************************************\r\n * author :  liyonghelpme\r\n * email  :  233242872@qq.com  \r\n * history:  \r\n * function: 命令处理单元 挂在一个对象身上，向这个单元注册处理函数， 外部将命令输入到该单元由单元处理，暂时只实现了键盘输入，并且为了避免输入队列太长做了优化\r\n * \r\n * 命令列表:\r\n * move h v   移动  键盘输入原始的移动\r\n * move_attack enemyId masterId \"adjustPos\"/\"attackByHand\"/\"spring\"/\"buff\" skillId 按下攻击 敌人的Id  或者移动主人的id 或者是 调整slave相对于Master的位置\r\n * move_keyboard 使用键盘移动\r\n * idle \"relive\" 进入空闲状态 没有键盘输入了\r\n * relive 复活\r\n * skill actionid targetId rotateY 技能Id 攻击目标Id \r\n * death 死亡\r\n * TryToMove x y z cb ignoreCollision rate 移动执行速率  将这个命令传给MonsterMoveAI\r\n * updatehp curhp hp 血量改变\r\n * hurt  怪物受伤状态 \r\n *  \r\n * ---moveToMaster 移动靠近主角 move_attack TryToMove\r\n * ---moveToMasterEnemy 移动攻击主角附近的敌人\r\n * attackNearbyEnemy 攻击自己附近的敌人\r\n * death_fly 死亡击飞\r\n * insert_command move_keyboard 插入一个命令供子状态监测是否可以切断当前的状态 例如Attack1  Attack2 Attack3 idle的时候 如果监测到insert时 则等待切断\r\n * networkCommand moveTo rotateY x y z \r\n * networkCommand skill actionId targetId rotateY\r\n * *******************************************************/\r\n";
        private static Dictionary<string, CmdHandler> publicCmdhandler = new Dictionary<string, CmdHandler>();

        public void AddCommand(string cmd, bool printOut = true, float rate = 1)
        {
            if (printOut)
            {
                Log.AI(base.gameObject, " addCommand " + cmd);
            }
            string str = string.Empty;
            Command command2 = new Command();
            char[] separator = new char[] { ' ' };
            command2.cmd = cmd.Split(separator);
            command2.stringCmd = cmd;
            command2.source = str;
            Command item = command2;
            item.rate = rate;
            if (this.cmdList.Count > 20)
            {
                Log.AI(base.gameObject, " Avoid Too Many Command 避免大量命令");
                this.cmdList[this.cmdList.Count - 1] = item;
            }
            else
            {
                this.cmdList.Add(item);
            }
        }

        private void AddCommandImmediately(string cmd)
        {
            Log.AI(base.gameObject, " addCommand Imm");
            Command command2 = new Command();
            char[] separator = new char[] { ' ' };
            command2.cmd = cmd.Split(separator);
            command2.stringCmd = cmd;
            Command command = command2;
            this.RunCommand(command);
        }

        public static void AddCommandStatic(GameObject g, string cmd, float rate = 1)
        {
            if (g != null)
            {
                CommandHandler component = g.GetComponent<CommandHandler>();
                if (component != null)
                {
                    component.AddCommand(cmd, true, rate);
                }
            }
        }

        public static void AddCommandStaticImmediately(GameObject g, string cmd)
        {
            if (g != null)
            {
                CommandHandler component = g.GetComponent<CommandHandler>();
                if (component != null)
                {
                    component.AddCommandImmediately(cmd);
                }
            }
        }

        public void AddHandler(string cmd, CmdHandler cmdHandler)
        {
            Log.AI(base.gameObject, string.Concat(new object[] { " handler is ", cmd, " handler ", cmdHandler }));
            this.cmdHandlers.Add(cmd, cmdHandler);
        }

        public static bool CheckHasCommand(GameObject g)
        {
            CommandHandler component = g.GetComponent<CommandHandler>();
            Log.AI(g, " CheckHasCommand " + component);
            if (component != null)
            {
                Log.AI(g, " CommandList " + component.cmdList.Count);
                return (component.cmdList.Count > 0);
            }
            return false;
        }

        public void Execute()
        {
            while (this.cmdList.Count > 0)
            {
                Command cmd = this.cmdList[0];
                this.cmdList.RemoveAt(0);
                this.RunCommand(cmd);
            }
        }

        private void RunCommand(Command cmd)
        {
            if (this.cmdHandlers.ContainsKey(cmd.cmd[0]))
            {
                this.cmdHandlers[cmd.cmd[0]](cmd);
            }
            else if (publicCmdhandler.ContainsKey(cmd.cmd[0]))
            {
                publicCmdhandler[cmd.cmd[0]](cmd);
            }
            else
            {
                Log.AI(base.gameObject, " Command Not Handler " + cmd.stringCmd);
            }
        }

        public delegate void CmdHandler(CommandHandler.Command cmd);

        public class Command
        {
            public string[] cmd;
            public int cmdId = maxId++;
            public bool isRunning;
            private static int maxId;
            public float rate = 1f;
            public string source;
            public string stringCmd;
            public float time;
        }
    }
}

